﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Linq.Extensions;
using Abp.Runtime.Session;
using Abp.UI;
using SingleUserMall.Common;
using SingleUserMall.Items;
using SingleUserMall.Orders;
using SingleUserMall.Orders.VO;
using SingleUserMall.ShoppingCarts.Form;
using SingleUserMall.ShoppingCarts.VO;
using SingleUserMall.Stores;
using static SingleUserMall.Items.Item;

namespace SingleUserMall.ShoppingCarts
{
    [AbpAuthorize]
    public class ShoppingCartAppService : SingleUserMallAppServiceBase, IShoppingCartAppService
    {
        private readonly IRepository<ShoppingCart, long> _shoppingCartRepository;
        private readonly IRepository<Order, long> _orderRepository;
        private readonly IRepository<OrderDetail, long> _orderDetailRepository;
        private readonly IRepository<ItemSpec, long> _itemSpecRepository;
        private readonly IRepository<GroupOrder, long> _groupOrderRepository;
        private readonly IRepository<GroupOrderDetail, long> _groupOrderDetailRepository;
        private readonly IRepository<Store> _storeRepository;
        private readonly IRepository<ItemBargain, long> _itemBargainRepository;
        public ShoppingCartAppService(
            IRepository<ShoppingCart, long> shoppingCartRepository,
            IRepository<Order, long> orderRepository,
            IRepository<OrderDetail, long> orderDetailRepository,
            IRepository<ItemSpec, long> itemSpecRepository,
            IRepository<GroupOrder, long> groupOrderRepository,
            IRepository<GroupOrderDetail, long> groupOrderDetailRepository,
            IRepository<Store> storeRepository,
            IRepository<ItemBargain, long> itemBargainRepository
            )
        {
            _shoppingCartRepository = shoppingCartRepository;
            _orderRepository = orderRepository;
            _orderDetailRepository = orderDetailRepository;
            _itemSpecRepository = itemSpecRepository;
            _groupOrderRepository = groupOrderRepository;
            _groupOrderDetailRepository = groupOrderDetailRepository;
            _storeRepository = storeRepository;
            _itemBargainRepository = itemBargainRepository;
        }
        public async Task AddShoppingCartItemAsync(ShoppingCartItemForm form)
        {
            var userId = AbpSession.GetUserId();
            var shoppingCart = form.MapTo<ShoppingCart>();
            shoppingCart.UserId = userId;
            shoppingCart.StoreId = _itemSpecRepository.FirstOrDefault(x => x.Id == form.ItemSpecId).Item.StoreId;
            var query = await _shoppingCartRepository.FirstOrDefaultAsync(p => p.ItemSpecId == form.ItemSpecId && p.UserId == userId);
            if (query != null)
            {
                query.Qty += form.Qty;
                await _shoppingCartRepository.UpdateAsync(query);
            }
            else
            {
                shoppingCart.ShoppingCartType = form.ShoppingCartType;
                await _shoppingCartRepository.InsertAsync(shoppingCart);
            }
        }


        public async Task<OrderVO> BargainBuyAsync(ShoppingCartItemForm form)
        {
            var userId = AbpSession.GetUserId();
            var user = await UserManager.FindByIdAsync(userId);
            var bargainItem = _itemBargainRepository.FirstOrDefault(form.BargainId.Value);
            if (bargainItem == null)
            {
                throw new UserFriendlyException("商品砍价记录不存在");
            }
            else if (bargainItem.UserId != userId && !bargainItem.UserList.Contains(userId.ToString()))
            {
                throw new UserFriendlyException("该砍价不是您发起或参与的 不能购买");
            }
            else
            {
                var hasUnPaidOrder = _orderRepository.Count(x => x.UserId == userId && x.BargainItemId == form.BargainId && x.Status == OrderStatus.WaitPay && DbFunctions.TruncateTime(x.CreationTime) == DbFunctions.TruncateTime(DateTime.Now)) > 0;
                if (hasUnPaidOrder)
                {
                    throw new UserFriendlyException("该砍价生成的订单您还未支付 不能购买");
                }

                var paidOrder = _orderRepository.Count(x => x.UserId == userId && x.BargainItemId == form.BargainId && x.Status == OrderStatus.Paid && DbFunctions.TruncateTime(x.CreationTime) == DbFunctions.TruncateTime(DateTime.Now)) > 0;
                if (paidOrder)
                {
                    throw new UserFriendlyException("您已经在今天购买过了 请明天再来");
                }
            }
            var itemSpec = _itemSpecRepository.FirstOrDefault(bargainItem.ItemSpec.Id);
            if (itemSpec == null)
            {
                throw new UserFriendlyException("商品规格不存在或已下架");
            }
            var item = itemSpec.Item;
            if (!item.IsBargain)
            {
                throw new UserFriendlyException("该商品没有参加砍价");
            }

            if(item.IsSaleOut)
            {
                throw new UserFriendlyException("您来晚了 该商品已售罄");
            }
            var amount = itemSpec.BargainPrice * form.Qty;
            var order = new Order
            {
                UserId = userId,
                ItemId = item.Id,
                OrderNo = Functions.NewOrderNo(),
                BargainItemId = bargainItem.Id,
                ShoppingCartType = ShoppingCartType.ShoppingItems,
                IsBargarin = true,
            };
            OrderManager.SetDefaultAddress(order, userId);
            var orderId = await _orderRepository.InsertAndGetIdAsync(order);
            await CurrentUnitOfWork.SaveChangesAsync();
            _orderDetailRepository.Insert(new OrderDetail
            {
                OrderId = orderId,
                ItemSpecId = itemSpec.Id,
                Price = itemSpec.BargainPrice,
                Qty = form.Qty,
                Freight = itemSpec.Item.Freight * form.Qty
            });
            await CurrentUnitOfWork.SaveChangesAsync();
            order = await _orderRepository.FirstOrDefaultAsync(orderId);
            order.Amount = amount;
            await OrderManager.ComputerAmountAsync(order);
            order.Status = OrderStatus.WaitPay;
            return order.ToVO<Order, OrderVO>((o, vo) =>
            {
                vo.OrderDetails = o.OrderDetails.Where(x => x.IsRefund == false).ToList().ToListVO<OrderDetail, OrderDetailVO>((d, dvo) =>
                {
                    var _spec = OrderManager.GetPositiveItemSpec(d.ItemSpecId);
                    dvo.inItem = _spec.Item;
                    dvo.inItemSpec = _spec;
                    dvo.Price = _spec.BargainPrice;
                });
            });
        }

        public async Task<OrderVO> BuyAsync(ShoppingCartItemForm form)
        {
            var userId = AbpSession.GetUserId();
            var user = await UserManager.FindByIdAsync(userId);
            var itemSpec = _itemSpecRepository.FirstOrDefault(form.ItemSpecId);

            if (itemSpec == null)
            {
                throw new UserFriendlyException("商品规格不存在或已下架");
            }
            if (itemSpec.Item.IsSaleOut)
            {
                throw new UserFriendlyException("您来晚了 该商品已售罄");
            }
            var amount = (user.IsVip ? (user.VipLevel > 1 ? itemSpec.SuperVipPrice : itemSpec.VipPrice) : itemSpec.Price) * form.Qty;
            var order = new Order
            {
                UserId = userId,
                ItemId = itemSpec.ItemId,
                OrderNo = Functions.NewOrderNo(),
                IsFriend = form.IsFriend,
                IsFriendAddress = form.IsFriendAddress,
                FriendUserId = form.FriendUserId,
                IsPackPrice = false,
                ShoppingCartType = form.ShoppingCartType,
                DividendItemStatus = DividendStatus.Start,
                AllBenefitForFriend = form.AllBenefitForFriend
            };
            if (!string.IsNullOrEmpty(itemSpec.Item.MinTreeNumber) && itemSpec.Item.ItemCategoryId == 7  && itemSpec.Item.ItemType == ItemsType.ShoppingItems)
            {
                var lastOrder = _orderRepository.GetAll().Where(x => x.ItemId == itemSpec.ItemId && x.Status >= OrderStatus.Paid).OrderByDescending(x => x.CreationTime).FirstOrDefault();
                if (lastOrder == null)
                {
                    order.MinTreeNumber = itemSpec.Item.MinTreeNumber;
                    order.MaxTreeNumber = (long.Parse(itemSpec.Item.MinTreeNumber) + form.Qty - 1).ToString();
                }
                else
                {
                    order.MinTreeNumber = (long.Parse(lastOrder.MaxTreeNumber) + 1).ToString();
                    order.MaxTreeNumber = (long.Parse(lastOrder.MaxTreeNumber) + form.Qty).ToString();
                }
            }
            var orderId = await _orderRepository.InsertAndGetIdAsync(order);
            await CurrentUnitOfWork.SaveChangesAsync();
            _orderDetailRepository.Insert(new OrderDetail
            {
                OrderId = orderId,
                ItemSpecId = itemSpec.Id,
                Price = user.IsVip ? (user.VipLevel > 1 ? itemSpec.SuperVipPrice : itemSpec.VipPrice) : itemSpec.Price,
                Qty = form.Qty,
                Freight = itemSpec.Item.Freight * form.Qty,
                PackPrice = itemSpec.Item.PackPrice

            });
            order.PackPrice = itemSpec.Item.PackPrice;
            OrderManager.SetDefaultAddress(order, userId);
            await CurrentUnitOfWork.SaveChangesAsync();
            order = await _orderRepository.FirstOrDefaultAsync(orderId);
            order.Amount = amount;
            await OrderManager.ComputerAmountAsync(order);
            order.Status = OrderStatus.WaitPay;
            return order.ToVO<Order, OrderVO>((o, vo) =>
            {
                vo.OrderDetails = o.OrderDetails.Where(x => x.IsRefund == false).ToList().ToListVO<OrderDetail, OrderDetailVO>((d, dvo) =>
                 {
                     var _spec = OrderManager.GetPositiveItemSpec(d.ItemSpecId);
                     dvo.inItem = _spec.Item;
                     dvo.inItemSpec = _spec;
                 });
            });
        }

        public async Task EditShoppingCartItemAsync(ShoppingCartForm form)
        {
            var shoppingCart = await _shoppingCartRepository.FirstOrDefaultAsync(form.ShoppingCartId);
            var itemSpec = _itemSpecRepository.FirstOrDefault(shoppingCart.ItemSpecId);
            if (!ItemManager.ValidateWholesale(itemSpec.ItemId, form.Qty, out int validCount))
            {
                throw new UserFriendlyException(string.Format("该商品为批发商品，请至少购买{0}件", validCount));
            }
            shoppingCart.Qty = form.Qty;
        }

        public async Task<ListResultDto<ShoppingCartItemByStoreVO>> GetShoppingCartAsync(MayHasStoreForm form)
        {
            try
            {
                var userId = AbpSession.GetUserId();

                var query = (from userShoppingCart in _shoppingCartRepository.GetAll().Where(x => x.UserId == userId)
                             join store in _storeRepository.GetAll() on userShoppingCart.StoreId equals store.Id
                             select store).Distinct();

                return await query.ToListResultDtoAsync<Store, ShoppingCartItemByStoreVO>((s, vo) =>
                {
                    var shoppingCartQuery = _shoppingCartRepository.GetAll().Where(x => x.UserId == userId && x.StoreId == s.Id);
                    vo.ShoppingCartItems = shoppingCartQuery.ToList().ToListVO<ShoppingCart, ShoppingCartItemVO>((sc, svo) =>
                    {
                        svo.inItem = sc.ItemSpec.Item;
                        svo.inItemSpec = sc.ItemSpec;
                    });
                });
            }
            catch (Exception e)
            {
                throw new UserFriendlyException(e.Message);
            }
        }

        public async Task<int> GetShoppingCartCountAsync(MayHasStoreForm form)
        {
            var userId = AbpSession.GetUserId();
            var query = _shoppingCartRepository.GetAll().Where(x => x.UserId == userId);
            return await query.CountAsync();
        }

        public async Task<OrderVO> GroupBuyAsync(GroupBuyItemForm form)
        {
            var _itemSpec = _itemSpecRepository.FirstOrDefault(form.ItemSpecId);
            if (_itemSpec.Item.IsSaleOut)
            {
                throw new UserFriendlyException("您来晚了 该商品已售罄");
            }
            var amount = _itemSpec.GroupPrice * form.Qty;
            var userId = AbpSession.GetUserId();
            var user = await UserManager.FindByIdAsync(userId);
            var order = new Order
            {
                UserId = userId,
                IsGroup = true,
                OrderNo = Functions.NewOrderNo(),
                ShoppingCartType = ShoppingCartType.ShoppingItems
            };
            OrderManager.SetDefaultAddress(order, userId);
            var orderId = await _orderRepository.InsertAndGetIdAsync(order);
            await CurrentUnitOfWork.SaveChangesAsync();
            var itemSpec = await _itemSpecRepository.FirstOrDefaultAsync(form.ItemSpecId);
            if (itemSpec == null)
            {
                throw new UserFriendlyException("商品规格不存在或已下架");
            }
            _orderDetailRepository.Insert(new OrderDetail
            {
                OrderId = orderId,
                ItemSpecId = itemSpec.Id,
                Price = itemSpec.GroupPrice,
                Qty = form.Qty,
                Freight = itemSpec.Item.Freight * form.Qty
            });
            await CurrentUnitOfWork.SaveChangesAsync();
            var groupOrder = new GroupOrder
            {
                UserId = user.Id,
                BeginTime = DateTime.Now,
                EndTime = DateTime.Now.AddDays(1),
                ItemId = itemSpec.ItemId,
                ItemSpecId = itemSpec.Id,
                Qty = form.Qty,
                TotalCount = itemSpec.Item.GroupCount
            };
            var groupOrderId = await _groupOrderRepository.InsertAndGetIdAsync(groupOrder);
            var groupOrderDetail = new GroupOrderDetail
            {
                GroupOrderId = groupOrderId,
                OrderId = orderId
            };
            await _groupOrderDetailRepository.InsertAsync(groupOrderDetail);
            order = await _orderRepository.FirstOrDefaultAsync(orderId);
            order.Amount = amount;
            await OrderManager.ComputerAmountAsync(order);
            order.Status = OrderStatus.WaitPay;
            return order.ToVO<Order, OrderVO>((o, vo) =>
            {
                vo.OrderDetails = o.OrderDetails.Where(x => x.IsRefund == false).ToList().ToListVO<OrderDetail, OrderDetailVO>((d, dvo) =>
                 {
                     var _itemspec = _itemSpecRepository.FirstOrDefault(d.ItemSpecId);
                     dvo.inItem = _itemspec?.Item;
                     dvo.inItemSpec = _itemspec;
                     dvo.Price = _itemspec.GroupPrice;
                 });
            });
        }

        public async Task<OrderVO> PartinGroupBuyAsync(PartinGroupBuyItemForm form)
        {
            var _itemSpec = _itemSpecRepository.FirstOrDefault(form.ItemSpecId);
            if (_itemSpec.Item.IsSaleOut)
            {
                throw new UserFriendlyException("您来晚了 该商品已售罄");
            }
            var amount = _itemSpec.GroupPrice * form.Qty;
            var userId = AbpSession.GetUserId();
            var user = await UserManager.FindByIdAsync(userId);
            var groupOrder = await _groupOrderRepository.FirstOrDefaultAsync(form.GroupOrderId);
            if(groupOrder.UserId == userId)
            {
                throw new UserFriendlyException("您是发起人不能再次参与拼团");
            }
            groupOrder.GroupOrderDetails.ToList().ForEach(x =>
            {
                if(x.Order.UserId == userId)
                {
                    throw new UserFriendlyException("您已经参与拼团 不能再次参与");
                }
            });
            var order = new Order
            {
                UserId = userId,
                IsGroup = true,
                OrderNo = Functions.NewOrderNo(),
                ShoppingCartType = ShoppingCartType.ShoppingItems
            };
            var orderId = await _orderRepository.InsertAndGetIdAsync(order);
            await CurrentUnitOfWork.SaveChangesAsync();
            var itemSpec = await _itemSpecRepository.FirstOrDefaultAsync(form.ItemSpecId);
            if (itemSpec == null)
            {
                throw new UserFriendlyException("商品规格不存在或已下架");
            }
            _orderDetailRepository.Insert(new OrderDetail
            {
                OrderId = orderId,
                ItemSpecId = itemSpec.Id,
                Price = itemSpec.GroupPrice,
                Qty = form.Qty,
                Freight = itemSpec.Item.Freight * form.Qty
            });
            await CurrentUnitOfWork.SaveChangesAsync();

            if (groupOrder.Status != GroupOrderStatus.Grouping)
            {
                throw new UserFriendlyException("该团购订单已关闭");
            }
            if (groupOrder.EndTime < DateTime.Now)
            {
               
                throw new UserFriendlyException("该团购订单已过期");
            }
            var groupOrderDetail = new GroupOrderDetail
            {
                GroupOrderId = form.GroupOrderId,
                OrderId = orderId
            };
            await _groupOrderDetailRepository.InsertAsync(groupOrderDetail);
            order = await _orderRepository.FirstOrDefaultAsync(orderId);
            order.Amount = amount;
            await OrderManager.ComputerAmountAsync(order);
            order.Status = OrderStatus.WaitPay;
            return order.ToVO<Order, OrderVO>((o, vo) =>
            {
                vo.OrderDetails = o.OrderDetails.Where(x => x.IsRefund == false).ToList().ToListVO<OrderDetail, OrderDetailVO>((d, dvo) =>
                 {
                     var _spec = OrderManager.GetPositiveItemSpec(d.ItemSpecId);
                     dvo.inItem = _spec.Item;
                     dvo.inItemSpec = _spec;
                     dvo.Price = _spec.GroupPrice;
                 });
            });
        }

        public async Task RemoveShoppingCartItemsAsync(ShoppingCartItemsForm form)
        {
            await _shoppingCartRepository.DeleteAsync(x => form.ShoppingCartIds.Contains(x.Id) && x.StoreId == form.storeId);
        }

        public async Task<OrderVO> RushBuyAsync(ShoppingCartItemForm form)
        {
            var userId = AbpSession.GetUserId();
            var user = await UserManager.FindByIdAsync(userId);
            var itemSpec = _itemSpecRepository.FirstOrDefault(form.ItemSpecId);
            if (itemSpec == null)
            {
                throw new UserFriendlyException("商品规格不存在或已下架");
            }
            var item = itemSpec.Item;
            if (!item.IsTimeLimit)
            {
                throw new UserFriendlyException("该商品没有参加抢购");
            }
            if (item.LimitBeginTime > DateTime.Now)
            {
                throw new UserFriendlyException("抢购尚未开始");
            }
            if (item.LimitEndTime < DateTime.Now)
            {
                throw new UserFriendlyException("抢购已经结束");
            }
            if (item.IsSaleOut)
            {
                throw new UserFriendlyException("您来晚了 该商品已售罄");
            }
            var amount = itemSpec.LimitPrice * form.Qty;
            var order = new Order
            {
                UserId = userId,
                OrderNo = Functions.NewOrderNo()
            };
            var orderId = await _orderRepository.InsertAndGetIdAsync(order);
            await CurrentUnitOfWork.SaveChangesAsync();
            _orderDetailRepository.Insert(new OrderDetail
            {
                OrderId = orderId,
                ItemSpecId = itemSpec.Id,
                Price = itemSpec.LimitPrice,
                Qty = form.Qty,
                Freight = itemSpec.Item.Freight * form.Qty
            });
            await CurrentUnitOfWork.SaveChangesAsync();
            order = await _orderRepository.FirstOrDefaultAsync(orderId);
            order.Amount = amount;
            await OrderManager.ComputerAmountAsync(order);
            order.Status = OrderStatus.WaitPay;
            return order.ToVO<Order, OrderVO>((o, vo) =>
            {
                vo.OrderDetails = o.OrderDetails.Where(x => x.IsRefund == false).ToList().ToListVO<OrderDetail, OrderDetailVO>((d, dvo) =>
                 {
                     var _spec = OrderManager.GetPositiveItemSpec(d.ItemSpecId);
                     dvo.inItem = _spec.Item;
                     dvo.inItemSpec = _spec;
                     dvo.Price = _spec.LimitPrice;
                 });
            });
        }

        public async Task<OrderVO> SettleAsync(ShoppingCartItemsForm form)
        {
            var userId = AbpSession.GetUserId();
            var user = await UserManager.FindByIdAsync(userId);
            var items = await _shoppingCartRepository.GetAllListAsync(x => form.ShoppingCartIds.Contains(x.Id));

            if (items.GroupBy(x => x.StoreId).Count() > 1)
            {
                throw new UserFriendlyException("不同商城商品需独立下单");
            }
            var order = new Order
            {
                UserId = userId,
                OrderNo = Functions.NewOrderNo(),
                ShoppingCartType = form.ShoppingCartType
            };
            var orderId = await _orderRepository.InsertAndGetIdAsync(order);
            var amount = items.Select(x => (user.IsVip ? (user.VipLevel > 1 ? x.ItemSpec.SuperVipPrice : x.ItemSpec.VipPrice) : x.ItemSpec.Price) * x.Qty).Sum();
            items.ForEach(item =>
            {
                var itemSpec = _itemSpecRepository.FirstOrDefault(item.ItemSpecId);
                if (itemSpec == null)
                {
                    throw new UserFriendlyException("商品规格不存在或已下架");
                }
                _orderDetailRepository.Insert(new OrderDetail
                {
                    OrderId = orderId,
                    ItemSpecId = itemSpec.Id,
                    Price = user.IsVip ? (user.VipLevel > 1 ? itemSpec.SuperVipPrice : itemSpec.VipPrice) : itemSpec.Price,
                    Qty = item.Qty,
                    Freight = itemSpec.Item.Freight * item.Qty
                });
                _shoppingCartRepository.Delete(item);
            });

            await CurrentUnitOfWork.SaveChangesAsync();
            order = await _orderRepository.FirstOrDefaultAsync(orderId);
            order.Amount = amount;
            await OrderManager.ComputerAmountAsync(order);
            order.Status = OrderStatus.WaitPay;
            return order.ToVO<Order, OrderVO>((o, vo) =>
            {
                int couponStoreId = 1;
                vo.OrderDetails = o.OrderDetails.Where(x => x.IsRefund == false).ToListVO<OrderDetail, OrderDetailVO>((d, dvo) =>
                 {
                     var _itemSpec = OrderManager.GetPositiveItemSpec(d.ItemSpecId);
                     dvo.inItem = _itemSpec.Item;
                     dvo.inItemSpec = _itemSpec;
                     couponStoreId = _itemSpec.Item.StoreId;
                 });
            });
        }
    }
}
